import { getUuid } from "@/utils/common.methods";
import { SiderMenuEnum } from "./@types";
import { Message } from "@arco-design/web-vue";
import { chatDB } from "@/db/chat";
import { AssetInfo } from "./asset";
import { SyncActionEnum, synchronousService } from "@/services/synchronous.service";

export type DrawModelSettingInfo = {
  width: number;
  height: number;
  guidance_scale: number;
  default_negative_prompt: string; // 负面提示词
  steps: number;
};

export type DrawModelInfo = {
  name: string;
  alias: string;
  inference: DrawModelSettingInfo;
};

export type AIDrawMenuImageInfo = {
  uid: string;
  task_id: string;
  forward: string;
  exclude?: string;
  model: string;
  isShare?: number; // 是否已分享
  img: AssetInfo;
  // 参考图
  original?: AssetInfo;
  // 参考图权重
  picture_weight: number;
  step?: number;
  ratio?: string;
  width?: number;
  height?: number;
};

export type AIDrawMenuInfo = {
  uid: string;
  label: string;
  type: SiderMenuEnum;
  image?: AIDrawMenuImageInfo;
  childrens?: AIDrawMenuInfo[];
};

export type ChatFileInfo = {
  currKey?: string;
  menus?: AIDrawMenuInfo[];
};

export class AIDrawModel {
  public LOCAL_STORAGE_KEY = "chat-aidraw";
  private _data = <ChatFileInfo>{};
  private _models: DrawModelInfo[] = [];

  private _default = {
    forward: "1只穿着机械化装甲套装的布娃娃猫，透明头盔，Fluffy，使用爆炸火箭喷气背包飞行，太空舱中，爆炸背后是火花冒烟的火箭引擎，最佳画质，高分辨率，清晰对焦，高细节，电影阴影，侧光效果，动态模糊，电影灯光",
    exclude: "水印，带有水印的，文本，JPEG图像瑕疵，低质量，不安全内容，裸体，裸露，色情，最差质量，低质量，裁剪，超出画面，绘制不精细，解剖错误，额外的四肢，缺失肢体，漂浮的肢体，变异的手和手指，脱节的肢体，额外的腿，融合的手指，过多的手指，长颈鸟，变异，变异的，丑陋，恶心，截肢，模糊，签名",
  };

  constructor() {}

  public async setData(): Promise<void> {
    let dataStr = (await chatDB.getStr(this.LOCAL_STORAGE_KEY))?.value ;
    this._data = dataStr ? JSON.parse(dataStr) : {};
  }

  public setModels(list: DrawModelInfo[]): void {
    this._models = list;
  }

  public get models(): DrawModelInfo[] {
    return this._models;
  }

  /** 左侧目录 */
  public async menus(): Promise<AIDrawMenuInfo[]> {
    if (!this._data?.currKey) {
      await this.setData();
    }
    return this._data?.menus || [];
  }

  public async add(type: SiderMenuEnum, parent?: string): Promise<void> {
    const { exclude, forward } = this._default;
    const label = (type === SiderMenuEnum.Group ? "合集" : "会话") + getUuid(5);
    const uid = getUuid();
    const model = this._models[0];
    const item: AIDrawMenuInfo = { uid, label, type, image: { uid: getUuid(), task_id: "", img: {} as AssetInfo, picture_weight: 50, model: model?.name, forward, exclude, step: 30 } };
    if (parent) {
      this._data?.menus?.map((val) => {
        if (val.uid === parent) val.childrens = (val.childrens || []).concat(item);
        return val;
      });
    } else {
      this._data.menus = (this._data?.menus || []).concat(item);
    }
    this._data.currKey = uid;
    synchronousService.session(this.LOCAL_STORAGE_KEY, SyncActionEnum.Add, item, parent);
    await this.setLocalStorage("add");
  }

  public async edit(uid: string, label: string): Promise<void> {
    let item = {} as AIDrawMenuInfo;
    let parent = undefined;
    this._data.menus?.forEach((menu) => {
      if (menu.uid === uid) {
        menu.label = label;
        item = menu;
      }
      menu.childrens?.forEach((child) => {
        if (child.uid === uid) {
          child.label = label;
          item = child;
          parent = menu.uid;
        }
      });
    });
    synchronousService.session(this.LOCAL_STORAGE_KEY, SyncActionEnum.Update, item, parent);
    await this.setLocalStorage("edit");
  }
  public async update(menus: AIDrawMenuInfo[]) {
    this._data.menus = menus;
    // synchronousService.session(this.LOCAL_STORAGE_KEY, SyncActionEnum.Update, item, parent);
    await this.setLocalStorage("update");
  }

  public async remove(uid: string): Promise<void> {
    this._data.menus = this._data.menus?.filter((val) => {
      val.childrens = val.childrens?.filter((child) => child.uid !== uid);
      return val.uid !== uid;
    });
    this._data.currKey = this._data.menus[0]?.uid || "";
    synchronousService.session(this.LOCAL_STORAGE_KEY, SyncActionEnum.Update, { uid } as AIDrawMenuInfo);
    await this.setLocalStorage("remove");
  }

  public async setCurrKey(uid: string): Promise<void> {
    this._data.currKey = uid;
    await this.setLocalStorage("setCurrKey");
  }

  public get currKey(): string {
    return this._data?.currKey;
  }

  public get currMenu(): AIDrawMenuInfo {
    if (!this._data?.menus?.length) return;
    const key = this.currKey;
    for (const item of this._data?.menus) {
      if (item.uid === key) {
        if (!item.image?.model) {
          item.image.model = this.models[0]?.name;
        }
        return item;
      } else {
        if (item?.childrens) {
          for (const child of item?.childrens) {
            if (child.uid === key) {
              if (!child.image?.model) child.image.model = this.models[0].name;
              return child;
            }
          }
        }
      }
    }
    return null;
  }

  public async setPrompt(forward: string, exclude: string): Promise<void> {
    const uid = getUuid();
    const key = this._data.currKey;
    const image: AIDrawMenuImageInfo = { uid, task_id: "", img: {} as AssetInfo, forward, exclude, model: "", picture_weight: 50, width: 1024, height: 1024 };
    for (const item of this._data?.menus) {
      if (item.uid === key) item.image = image;
      if (item?.childrens) {
        for (const child of item?.childrens) {
          if (child.uid === key) child.image = image;
        }
      }
    }
    console.log(this._data);

    await this.setLocalStorage("setPrompt");
  }

  public async updateImage(task_id: string, img: AssetInfo, forward: string, exclude: string, model: string, picture_weight?: number, ratio?: string, original?: AssetInfo, width?: number, height?: number, step: number = 30): Promise<void> {
    let item = {} as AIDrawMenuInfo;
    let parent = undefined;
    const uid = getUuid();
    const key = this._data.currKey;
    const image: AIDrawMenuImageInfo = { uid, task_id, img, forward, exclude, model, picture_weight, width, height, step, ratio, original, isShare: 0 };
    for (const menu of this._data.menus) {
      if (menu.uid === key) {
        menu.label = forward?.slice(0, 10);
        menu.image = image;
        item = menu;
      }
      if (item?.childrens) {
        for (const child of item?.childrens) {
          if (child.uid === key) {
            child.label = forward?.slice(0, 10);
            child.image = image;
            item = child;
            parent = menu.uid;
          }
        }
      }
    }
    synchronousService.session(this.LOCAL_STORAGE_KEY, SyncActionEnum.Update, item, parent);
    await this.setLocalStorage("updateImage");
  }
  public async share(): Promise<void> {
    let item = {} as AIDrawMenuInfo;
    let parent = undefined;
    const key = this._data.currKey;
    for (const menu of this._data.menus) {
      if (menu.uid === key) {
        menu.image.isShare = 1;
        item = menu;
      }
      if (menu?.childrens) {
        for (const child of menu?.childrens) {
          if (child.uid === key) {
            child.image.isShare = 1;
            item = child;
            parent = menu.uid;
          }
        }
      }
    }
    synchronousService.session(this.LOCAL_STORAGE_KEY, SyncActionEnum.Update, item, parent);
    await this.setLocalStorage("updateImage");
  }

  /** 清空 */
  public async clear(): Promise<void> {
    this._data = {};
    synchronousService.clearSession(this.LOCAL_STORAGE_KEY);
    await this.setLocalStorage("clear");
  }

  private async setLocalStorage(source: string): Promise<void> {
    console.log("setLocalStoragesetloca >>> source :", source, this._data);
    await chatDB.set(this.LOCAL_STORAGE_KEY, JSON.stringify(this._data));
    // localStorage.setItem(this.LOCAL_STORAGE_KEY, JSON.stringify(this._data));
  }
}
